#pragma once
#include <string>
#include <sstream>
#include <vector>
#include <fstream>
#include <pthread.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <fcntl.h>

#include "Socket.hpp"
#include "Log.hpp"
extern Log log;

const std::string sep = "\r\n";
const std::string webroot = "./webroot";
const std::string homepage = "index.html";
class Request
{
public:
    Request()
    {
    }
    ~Request()
    {
    }
    void Deserialization(std::string req)
    {
        while (true)
        {
            size_t pos = req.find(sep);
            if (pos == std::string::npos)
                return;
            std::string temp = req.substr(0, pos);
            report_header.push_back(temp);
            req.erase(0, pos + sep.size());
        }
        text = req;
    }
    std::string ReadFile()
    {
       std::ifstream in(file_path);
        if(!in.is_open())
        {
            log(Fatal, "ifstream open %s error\n", file_path.c_str());
            exit(1);
        }
        std::string content;
        std::string line;
        while(std::getline(in, line))
        {
            content += line;
        }
        return content;
    }
    void Parse()
    {
        std::stringstream ss(report_header[0]);
        ss >> method >> url >> http_version;
        file_path = webroot;
        if (url == "/" || url == "/indext.html")
        {
            file_path += "/";
            file_path += homepage; //"./webroot/indext.html"
            return;
        }
        file_path += url;
    }
    void DebugReq()
    {
        std::cout << "-----------------------------------" << std::endl;
        for (auto &e : report_header)
        {
            std::cout << e << std::endl;
        }
        std::cout << text << std::endl;
        std::cout << "method:" << method << std::endl;
        std::cout << "url:" << url << std::endl;
        std::cout << "http_version:" << http_version << std::endl;
        std::cout << "file_path:" << file_path << std::endl;
        std::cout << "-----------------------------------" << std::endl;

    }

private:
    std::vector<std::string> report_header;
    std::string text;

    std::string method;
    std::string url;
    std::string http_version;
    std::string file_path;
};

class HttpServer;
struct ThreadData
{
    int sockfd;
    HttpServer *svr;
};

class HttpServer
{
public:
    HttpServer(uint16_t port) : _port(port)
    {
    }
    ~HttpServer()
    {
    }

public:
    void Start()
    {
        _listensock.Socket();
        _listensock.Bind(_port);
        _listensock.Listen();

        while (true)
        {
            std::string clientip;
            uint16_t clientport;
            int sockfd = _listensock.Accept(&clientip, &clientport);
            log(Info, "get a new link, sockfd:%d,[%s:%d]\n", sockfd, clientip.c_str(), clientport);
            ThreadData *td = new ThreadData();
            td->sockfd = sockfd;
            td->svr = this;
            pthread_t tid;
            pthread_create(&tid, nullptr, Routine, td);
        }
    }
    void FileHandler(int sockfd)
    {
        char buffer[10240];
        ssize_t n = recv(sockfd, buffer, sizeof(buffer) - 1, 0);
        if (n > 0)
        {
            buffer[n] = 0;
            // 反序列化
            Request req;
            req.Deserialization(buffer);
            req.Parse();
            req.DebugReq();
            
            //  处理请求
             std::string response_line = "HTTP/1.0 200 OK\r\n";
             std::string text = req.ReadFile();
             std::string response_header = "Content-Length:";
             response_header += std::to_string(text.size());
             response_header += "\n\r\n\r";
             std::string rep = response_line;
             rep += response_header;
             rep += text;
             send(sockfd, rep.c_str(), rep.size(), 0);
        }
        close(sockfd);
    }
    static void *Routine(void *arg)
    {
        ThreadData *td = static_cast<ThreadData *>(arg);
        pthread_detach(pthread_self());
        td->svr->FileHandler(td->sockfd);
        delete td;
        return nullptr;
    }

private:
    Sock _listensock;
    uint16_t _port;
};